#include "algorithmstrategy.h"

QImage cvMatToQImage(const Mat& mat)
{
    switch (mat.type()) {
    case CV_8UC1:
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        image.setColorCount(256);
        for (int i = 0; i < 256; ++i) {
            image.setColor(i, qRgb(i, i, i));
        }
        uchar* pSrc = mat.data;
        for (int row = 0; row < mat.rows; ++row) {
            uchar* pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }break;
    case CV_8UC3:
    {
        const uchar* pSrc = (const uchar*)mat.data;
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }break;
    case CV_8UC4:
    {
        const uchar* pSrc = (const uchar*)mat.data;
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }break;
    default:
        break;
    }
    return QImage();
}

Mat QImageTocvMat(const QImage &image)
{
    Mat mat;
    switch (image.format()) {
    case QImage::Format_Grayscale8:  // 灰度图，每个像素一个字节
    case QImage::Format_Indexed8:
        mat = Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_A2RGB30_Premultiplied:
        mat = Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        cvtColor(mat, mat, COLOR_BGRA2BGR);
        break;
    case QImage::Format_RGB888:
        mat = Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cvtColor(mat, mat, COLOR_RGB2BGR);
        break;
    }
    return mat;
}

// ------------------- 二值化 ------------------
BinaryAS::BinaryAS(const QString &name)
{
    m_name = name;
    m_hash["binary"] = THRESH_BINARY;
    m_hash["binary_inv"] = THRESH_BINARY_INV;
    m_hash["tozero"] = THRESH_TOZERO;
    m_hash["tozero_inv"] = THRESH_TOZERO_INV;
    m_hash["trunc"] = THRESH_TRUNC;
    m_hash["OSTU"] = THRESH_OTSU;
    m_hash["TRIANGLE"] = THRESH_TRIANGLE;
}

void BinaryAS::methodAS(Mat &mask, QPixmap *m_tmpPic, QPixmap *m_pic)
{
    qDebug() << "BinaryAS";
    if(m_hash.find(m_name) != m_hash.end())
    {
        Mat img = QImageTocvMat(m_tmpPic->toImage());   // 一直用任务执行前的原图操作
        Mat img2 = img.clone();

        if(m_hash[m_name] == THRESH_OTSU || m_hash[m_name] == THRESH_TRIANGLE)  // 大津法和三角形法
            cvtColor(img2, img2, COLOR_BGR2GRAY);

        if(img2.empty())
        {
            qDebug() << "请确定图片文件是否正确";
            return ;
        }

        threshold(img2, img2, m_threshold, m_maxValue, m_hash[m_name]);

        if(img2.type() == CV_8UC1)
            cvtColor(img2, img2, COLOR_GRAY2BGR);

        Mat ROI = img.clone();
        // 判断是否有掩码矩阵
        if(!mask.empty())
        {
            Mat tmp;
            img2.copyTo(tmp, mask);
            tmp.copyTo(ROI, mask);
        }
        else
        {
            ROI = img2.clone();
        }

        QImage dest = cvMatToQImage(ROI);
        *m_pic = QPixmap(QPixmap::fromImage(dest));
    }
    else
        return ;
}

void BinaryAS::setThreshold(int threshold)
{
    m_threshold = threshold;
}

void BinaryAS::setMaxValue(int max)
{
    m_maxValue = max;
}

void BinaryAS::setName(const QString &name)
{
    m_name = name;
}

// ------------------- 形态学处理 ------------------
MorphologicalAS::MorphologicalAS(const QString &name, const QString& shape, int kernel)
{
    m_name = name;
    m_shape = shape;
    m_kernel = Size(kernel,kernel);
    m_hash["矩形"] = MORPH_RECT;
    m_hash["圆形"] = MORPH_ELLIPSE;
}

void MorphologicalAS::methodAS(Mat &mask, QPixmap *m_tmpPic, QPixmap *m_pic)
{
    qDebug() << "MorphologicalAS";
    qDebug() << m_name;
    Mat img = QImageTocvMat(m_tmpPic->toImage());   // 一直用任务执行
    Mat img2 = img.clone();

    if(img2.empty())
        return ;

    Mat kernel = getStructuringElement(m_hash[m_shape], m_kernel);
    if(m_name == "腐蚀"){
        erode(img2, img2, kernel);
    }else if(m_name == "膨胀"){
        dilate(img2, img2, kernel);
    }

    if(img2.type() == CV_8UC1)
        cvtColor(img2, img2, COLOR_GRAY2BGR);

    Mat ROI = img.clone();

    if(!mask.empty()){
        Mat tmp;
        img2.copyTo(tmp, mask);
        tmp.copyTo(ROI, mask);
    }else{
        ROI = img2.clone();
    }

    QImage dest = cvMatToQImage(ROI);
    *m_pic = QPixmap::fromImage(dest);
}

void MorphologicalAS::setKernel(int kernel)
{
    m_kernel = Size(kernel,kernel);
}

void MorphologicalAS::setShape(const QString &shape)
{
    m_shape = shape;
}

// ------------------- 滤波 ------------------
FilteringAS::FilteringAS(const QString &name)
{
    m_name = name;
    m_kernel = Size(1,1);
}

void FilteringAS::methodAS(Mat &mask, QPixmap *m_tmpPic, QPixmap *m_pic)
{
    Mat img = QImageTocvMat(m_tmpPic->toImage());
    Mat img2 = img.clone();
    if(img2.empty())
    {
        qDebug() << "请确认图像文件名称是否正确";
        return ;
    }

    if("均值滤波" == m_name)
    {
        blur(img2, img2, m_kernel);
    }
    else if("高斯滤波" == m_name)
    {
        GaussianBlur(img2, img2, m_kernel, 0);
    }
    else if("中值滤波" == m_name)
    {
        medianBlur(img2, img2, m_kernel.height);
    }

    if(img2.type() == CV_8UC1)
        cvtColor(img2, img2, COLOR_GRAY2BGR);
    Mat ROI = img.clone();
    if(!mask.empty())
    {
        Mat temp;
        img2.copyTo(temp, mask);
        temp.copyTo(ROI, mask);
    }
    else
    {
        ROI = img2.clone();
    }

    QImage dest = cvMatToQImage(ROI);
    *m_pic = QPixmap(QPixmap::fromImage(dest));
}

void FilteringAS::setKernel(int kernel)
{
    m_kernel = Size(kernel, kernel);
}

// ------------------- 边缘检测 ------------------
EdgeDetectionAS::EdgeDetectionAS(const QString &name)
{
    m_name = name;
}

void EdgeDetectionAS::methodAS(Mat &mask, QPixmap *m_tmpPic, QPixmap *m_pic)
{
    qDebug()<< "edgeDetectionAS";
    Mat img = QImageTocvMat(m_tmpPic->toImage());
    Mat img2 = img.clone();
    if(img2.empty())
    {
        qDebug() << "请确认图像文件名称是否正确";
        return ;
    }
    cvtColor(img2, img2, COLOR_BGR2GRAY);
    if(QString("Canny") == m_name)
    {
        Canny(img2, img2, 50, 150);
    }
    else if("Sobel" == m_name)
    {
        Mat x, y, abs_x, abs_y;
        Sobel(img2, x, CV_16S, 1, 0);
        Sobel(img2, y, CV_16S, 0, 1);
        convertScaleAbs(x, abs_x);
        convertScaleAbs(y, abs_y);
        addWeighted(abs_x, 0.5, abs_y, 0.5, 0, img2);
    }
    else if("Laplacian" == m_name)
    {
        Laplacian(img2, img2, CV_8UC1);
        convertScaleAbs(img2, img2);
    }

    if(img2.type() == CV_8UC1)
        cvtColor(img2, img2, COLOR_GRAY2BGR);
    Mat ROI = img.clone();
    if(!mask.empty())
    {
        Mat temp;
        img2.copyTo(temp, mask);
        temp.copyTo(ROI, mask);
    }
    else
    {
        ROI = img2.clone();
    }

    QImage dest = cvMatToQImage(ROI);
    *m_pic = QPixmap(QPixmap::fromImage(dest));
}

// ------------------- 直方图 ------------------
EqualizeHistAS::EqualizeHistAS(const QString &name)
{
    m_name = name;
}

void EqualizeHistAS::methodAS(Mat &mask, QPixmap *m_tmpPic, QPixmap *m_pic)
{
    qDebug()<< "EqualizeHistAS";
    Mat img = QImageTocvMat(m_tmpPic->toImage());
    Mat img2 = img.clone();
    if(img2.empty())
    {
        qDebug() << "请确认图像文件名称是否正确";
        return ;
    }
    cvtColor(img2, img2, COLOR_BGR2GRAY);

    equalizeHist(img2, img2);

    if(img2.type() == CV_8UC1)
        cvtColor(img2, img2, COLOR_GRAY2BGR);
    Mat ROI = img.clone();
    if(!mask.empty())
    {
        Mat temp;
        img2.copyTo(temp, mask);
        temp.copyTo(ROI, mask);
    }
    else
    {
        ROI = img2.clone();
    }

    QImage dest = cvMatToQImage(ROI);
    *m_pic = QPixmap(QPixmap::fromImage(dest));
}

// ------------------- 彩色图像转换 ------------------
ColorToAS::ColorToAS(const QString &name)
{
    m_name = name;
}

void ColorToAS::methodAS(Mat &mask, QPixmap *m_tmpPic, QPixmap *m_pic)
{
    qDebug()<< "ColorToAS" << m_name;
    Mat img = QImageTocvMat(m_tmpPic->toImage());
    Mat img2 = img.clone();
    if(img2.empty())
    {
        qDebug() << "请确认图像文件名称是否正确";
        return ;
    }

    if(m_name == "HSV转RGB")
        cvtColor(img2, img2, COLOR_HSV2BGR);
    else if(m_name == "RGB转HSV")
        cvtColor(img2, img2, COLOR_BGR2HSV);

    if(img2.type() == CV_8UC1)
        cvtColor(img2, img2, COLOR_GRAY2BGR);
    Mat ROI = img.clone();
    if(!mask.empty())
    {
        Mat temp;
        img2.copyTo(temp, mask);
        temp.copyTo(ROI, mask);
    }
    else
    {
        ROI = img2.clone();
    }

    QImage dest = cvMatToQImage(ROI);
    *m_pic = QPixmap(QPixmap::fromImage(dest));
}
